/*
    storageX 1.2 storage对象化储存 uniAPP版，代码有注释，可以自己改
    不支持function的储存
    不支持对象的迭代
    author:https://www.dumogu.top/bloginfo/8661a212e0  (一篇文字博客)
	npm install storagex-js
*/
/*jshint esversion: 9 */
//将字符串转化为 对象 || 其他数据格式
function stringToObject(value){
    try {
        return JSON.parse(value);
    } catch(e) {
        if(value === 'undefined') return undefined;  //排除无法转换undefined的情况
        return value;
    }
}
//根据键名清空
function removeItem(key){
    uni.removeStorageSync(key);
}
//根据键名写入(转化为字符串)
const taskList = {};  //任务队列
function setItem(key,value){
    if(typeof key !== "string" || !key) throw "key 必须是字符串 || key 不能为空";
    if(typeof value == "function") throw "value 不能是function";
    //性能优化，防止频繁操作 (针对大数据会有明显加快，小数据可能会花费更多的时间)
    clearTimeout(taskList[key]);  //取消任务
    taskList[key] = setTimeout(()=>{
		if(value instanceof Object){  //如果是对象，转化为字符串（字符串在转化会多两个引号）
			value = JSON.stringify(value);
		};
		uni.setStorageSync(key,value);
    },0);
}
//根据键名获取(转化为对象)
function getItem(key){
	return stringToObject(uni.getStorageSync(key));
}
//深层对象代理(<目标对象>,<统一的set回调函数>)
function deepProxy(target,setFn,getFn){
    if(typeof target == "function") throw "target 不能是function";
    if(!(target instanceof Object)) return target;
    for(let index in target){
        if(target[index] instanceof Object){  //如果是对象的话转成代理对象
            target[index] = deepProxy(target[index],setFn,getFn);
        }
    }
    return new Proxy(
        target,
        {
            set(_target,_key,_value){
                if(_value instanceof Object){  //如果是对象的话转成代理对象
                    //需要克隆防止引用对象被修改时影响到代理对象 没有克隆（数据进行json化时会触发监听进行赋值函数，不克隆比较好）
                    _value = deepProxy(_value,setFn,getFn);
                }
                let r = Reflect.set(_target, _key, _value);
                setFn();
                return r;
            },
			get(_target,_key){
			    getFn();
			    return _target[_key];
			},
            deleteProperty(_target, _key) {
                let r = Reflect.deleteProperty(_target, _key);
                setFn();
                return r;
            }
        },
    );
}
//storage本地储存对象化代理，只有两种模式(只针对数据)
function storageX(key,target={}){
    if(typeof target == "function") throw "target 不能是function";
    if(!key){  //表示代理整个localStorage (key表示localStorage的key，不深度代理)
        return new Proxy(
            {},
            {
                get(_target,_key){  //获取某个键的值
                    if(typeof _key !== "string") throw "key 必须是字符串";
                    if(_key === "removeItem") return removeItem;  //返回清除方法
					_target[_key] = getItem(_key);
                    return _target[_key];
                },
                set(_target,_key,_value){  //写入某个键的值
                    if(_key === "removeItem") throw "removeItem是内置属性，不能更改";  //添加清除方法
                    let r = Reflect.set(
                        _target, 
                        _key, 
                        _value,
                    );
                    setItem(_key,_value);
                    return r;
                },
            },
        );
    }else{  //表示代理一个键，对应一个对象（深度代理）
        if(typeof key !== "string") throw "key 必须是字符串";
        if(!(target instanceof Object)) throw "target 必须是对象";
        let oldTarget = getItem(key);
        if(!oldTarget){
            setItem(key,target);  //初始化
        }else{
            target = oldTarget;  //如果键中有值则以该值为准
            if(!(target instanceof Object)) throw "key 中有原始值且不能转化为对象";
        }
        return deepProxy(
            target,
            function(){
                setItem(key,target);
            },
			function(){
				setTimeout(()=>{  //防止存储时异步没有执行
					if(!getItem(key)){  //如果该键在使用过程中清空的话向外抛出异常
						throw "key 在使用过程中已被清空，至少是一个空对象";
					}
				},0);
			},
        );
    }
}
export {
    storageX,
};